
import Canvas2Image from "../../plugins/utils/Canvas2Image";

export default class MPos{
    static setVP(option){
        let viewer = window.cesiumViewer;
        viewer.camera.setView({
            destination:Cesium.Cartesian3.fromDegrees(
                parseFloat(option.lon),parseFloat( option.lat), parseFloat(option.height)),
            orientation:{
                heading : Cesium.Math.toRadians(parseFloat(option.heading)), // 方向
                pitch : Cesium.Math.toRadians(parseFloat(option.pitch)),// 倾斜角度
                roll : Cesium.Math.toRadians(parseFloat(option.roll))
            }
        });
    }
    static getVP(){
        let viewer = window.cesiumViewer;
        let p3 = viewer.scene.pickPosition(new Cesium.Cartesian2(400,400));
        return {
            pos:viewer.camera.position,
            heading:viewer.camera.heading,
            pitch:viewer.camera.pitch,
            roll:viewer.camera.roll,
            posCart:viewer.camera.positionCartographic
        }
    }
    static setVPXYZ(option){
        let viewer = window.cesiumViewer;
        viewer.camera.setView({
            destination:new Cesium.Cartesian3(parseFloat(option.x),parseFloat( option.y), parseFloat(option.z)),
            orientation:{
                heading : Cesium.Math.toRadians(parseFloat(option.heading)), // 方向
                pitch : Cesium.Math.toRadians(parseFloat(option.pitch)),// 倾斜角度
                roll : Cesium.Math.toRadians(parseFloat(option.roll))
            }
        });
    }
    static getPosOriFormViewMatrix(mat){
        let direction = new Cesium.Cartesian3();
        let up = new Cesium.Cartesian3();
        let pos = new Cesium.Cartesian3();

        let mat3 = new Cesium.Matrix3();
        Cesium.Matrix4.getMatrix3(mat,mat3);

        direction.x = mat3[2] *-1;
        direction.y = mat3[5] *-1;
        direction.z = mat3[8] *-1;

        up.x = mat3[1];
        up.y = mat3[4];
        up.z = mat3[7];

        let pw = new Cesium.Cartesian3(-mat[12],-mat[13],-mat[14]);
        let mat3i = new Cesium.Matrix3();
        Cesium.Matrix3.inverse(mat3,mat3i);
        Cesium.Matrix3.multiplyByVector(mat3i,pw,pos);

        let po = {};
        po.direction = direction;
        po.up = up;
        po.position = pos;
        return po;
    }

    static pickingRay(t) {
        let t0 = new Cesium.Cartesian4(0,0,0,1);
        //let t1 = new Cesium.Cartesian4(0,0,-1,1);
        let t1 = new Cesium.Cartesian4(t[0][0],t[0][1]*-1,-1,1);
        let camera = window.cesiumViewer.camera;
        // let nxx = Math.tan(camera.frustum.fov / 2);
        // let nyy = Math.tan(camera.frustum.fov / (2 * camera.frustum.aspectRatio));
        // t1.x = t1.x / nxx;
        // t1.y = t1.y * -1 / nyy;
        t0 = Cesium.Matrix4.multiplyByVector(camera.inverseViewMatrix,t0,t0);
        t1 = Cesium.Matrix4.multiplyByVector(camera.inverseViewMatrix,t1,t1);
        t0 = new Cesium.Cartesian3(t0.x,t0.y,t0.z);
        t1 = new Cesium.Cartesian3(t1.x,t1.y,t1.z);
        let dir = new Cesium.Cartesian3();
        Cesium.Cartesian3.subtract(t1, t0 , dir);
        Cesium.Cartesian3.normalize(dir,dir);
        let ray = new Cesium.Ray(t0, dir);
        let result = window.cesiumViewer.scene.globe.pick(ray, window.cesiumViewer.scene);
        return result;
    }

    static setVPMatrix(option){
        // let t =[3.6087762051993195,-8.468501922674477,4.876456279773265];
        // let r = option.r;

        // let mat0 = new Cesium.Matrix3(
        //     0.9990569345613338, -0.025451311487005038, 0.03517772375384962,
        //     0.02840786218175912, 0.9958662358702968, -0.08627533610359958,
        //     -0.032836486888412585, 0.08719329674417814, 0.9956500861907809
        // );
        let t =option.t;
        let r = option.r;
        let t0 = new Cesium.Cartesian3(t[0],t[1],t[2]);
        let mat0 = new Cesium.Matrix3(
            r[0][0], r[0][1], r[0][2],
            r[1][0], r[1][1], r[1][2],
            r[2][0], r[2][1], r[2][2]
        );

        // let mat1 = new Cesium.Matrix3();
        // Cesium.Matrix3.inverse(mat0,mat1);
        let viewmatrix = null;
        let camera = window.cesiumViewer.camera;
        if(window.lastViewMatrix){
            viewmatrix = window.lastViewMatrix
        }else{
            viewmatrix = camera.viewMatrix
        }
        //MAT3 = MAT1-3 * MAT1
        let mat = Cesium.Matrix4.fromRotationTranslation(mat0,t0);
        let mat2 = new Cesium.Matrix4();
        Cesium.Matrix4.multiply(mat,viewmatrix,mat2);
        let po = MPos.getPosOriFormViewMatrix(mat2);
        camera.setView({
            destination : po.position,
            orientation : {
                direction : po.direction ,
                up : po.up
            }
        });
        //window.lastViewMatrix = null;
        // let mat2 = new Cesium.Matrix4();
        // Cesium.Matrix4.multiply(camera.inverseViewMatrix,mat,mat2);
        // let mat3 = new Cesium.Matrix4();
        // Cesium.Matrix4.getMatrix3(mat2,mat3);
        // let pos = new Cesium.Cartesian3();
        // Cesium.Cartesian3.add(camera.position , new Cesium.Cartesian3(t[0],t[1],t[2]),pos);
        // let direction = new Cesium.Cartesian3();
        // let up = new Cesium.Cartesian3();
        //
        // let mat2 = new Cesium.Matrix3();
        // Cesium.Matrix4.getMatrix3(camera.viewMatrix,mat2);
        // let mat3 = new Cesium.Matrix3();
        // Cesium.Matrix3.multiply(mat0,mat2,mat3);
        //
        // // Cesium.Matrix3.getColumn(mat2, 2, direction);
        // // Cesium.Matrix3.getColumn(mat2, 2, up);


    }
    static capturePicture(){
        let viewer = window.cesiumViewer;
        var canvas = viewer.scene.canvas;
        var img = Canvas2Image.convertToImage(canvas, canvas.width,  canvas.height,'jpeg');
        //let img = canvas.toDataURL("image/png")
        var loadImg = document.createElement('a')
        loadImg.href = img.src
        loadImg.download = 'earth.jpg'
        loadImg.click()
    }


    static drawingBufferToWgs84Coordinates(
        scene,
        frum,
        drawingBufferPosition,
        depth,
        result
    ) {
        var context = scene.context;
        var uniformState = context.uniformState;
        //var currentFrustum = frustum;
        var near = frum.near;
        var far = frum.far;


        if (scene.frameState.useLogDepth)
        {
            // transforming logarithmic depth of form
            // log2(z + 1) / log2( far + 1);
            // to perspective form
            // (far - far * near / z) / (far - near)
            var log2Depth = depth * uniformState.log2FarDepthFromNearPlusOne;
            var depthFromNear = Math.pow(2.0, log2Depth) - 1.0;
            depth = (far * (1.0 - near / (depthFromNear + near))) / (far - near);
        }

        var scratchNDC = new Cesium.Cartesian4();
        var scratchWorldCoords = new Cesium.Cartesian4();

        var viewport = scene.view.passState.viewport;
        var ndc = Cesium.Cartesian4.clone(Cesium.Cartesian4.UNIT_W, scratchNDC);
        ndc.x = ((drawingBufferPosition.x - viewport.x) / viewport.width) * 2.0 - 1.0;
        ndc.y =
            ((drawingBufferPosition.y - viewport.y) / viewport.height) * 2.0 - 1.0;
        ndc.z = depth * 2.0 - 1.0;
        ndc.w = 1.0;

        var worldCoords;
        var frustum = scene.camera.frustum;
        // if (!Cesium.defined(frustum.fovy)) {
        //     if (Cesium.defined(frustum._offCenterFrustum)) {
        //         frustum = frustum._offCenterFrustum;
        //     }
        //     worldCoords = scratchWorldCoords;
        //     worldCoords.x =
        //         (ndc.x * (frustum.right - frustum.left) + frustum.left + frustum.right) *
        //         0.5;
        //     worldCoords.y =
        //         (ndc.y * (frustum.top - frustum.bottom) + frustum.bottom + frustum.top) *
        //         0.5;
        //     worldCoords.z = (ndc.z * (near - far) - near - far) * 0.5;
        //     worldCoords.w = 1.0;
        //
        //     worldCoords = Cesium.Matrix4.multiplyByVector(
        //         uniformState.inverseView,
        //         worldCoords,
        //         worldCoords
        //     );
        // } else {
        //     worldCoords = Cesium.Matrix4.multiplyByVector(
        //         // uniformState.inverseViewProjection,
        //         uniformState.inverseProjection,
        //         ndc,
        //         scratchWorldCoords
        //     );
        //
        //     // Reverse perspective divide
        //     var w = 1.0 / worldCoords.w;
        //     Cesium.Cartesian3.multiplyByScalar(worldCoords, w, worldCoords);
        // }
        worldCoords = Cesium.Matrix4.multiplyByVector(
            // uniformState.inverseViewProjection,
            frum.invporj,
            ndc,
            scratchWorldCoords
        );

        // Reverse perspective divide
        var w = 1.0 / worldCoords.w;
        Cesium.Cartesian3.multiplyByScalar(worldCoords, w, worldCoords);
        return Cesium.Cartesian3.fromCartesian4(worldCoords, result);
    };

    static captureDepthImage(){
        let viewer = window.cesiumViewer;
        let width = viewer.scene.view.viewport.width;
        let height = viewer.scene.view.viewport.height;
        var canvastext = document.createElement('canvas');
        canvastext.width =width;
        canvastext.height = height;
        var ctx = canvastext.getContext('2d');
        var imgData=ctx.createImageData(width,height);
        var depthlist = MPos.captureDepthList();


        let t1 = 0;
        let min = 0;
        let max = 1;
        for (let t = 0;t<depthlist.length;t++){
            let d = depthlist[t];
            if(d >0 && d < 1){
                t1 = t;
                min = d;
                max = d;
                break;
            }
        }

        for (let t = t1;t<depthlist.length;t++){
            let d = depthlist[t];
            if(d >0 && d < 1){
                if(min > d){
                    min = d;
                }
                if(max < d){
                    max = d;
                }
            }
        }
        for (var i=0;i<imgData.data.length/4;i+=1)
        {
            let depth = depthlist[i];
            if(depth<=0){
                depth = max;
            }
            depth = (depth - min)/(max - min);
            depth = depth * 255;
            imgData.data[i*4+0]=depth;
            imgData.data[i*4+1]=depth;
            imgData.data[i*4+2]=depth;
            imgData.data[i*4+3]=255;
        }
        ctx.putImageData(imgData,0,0);
        var img = Canvas2Image.convertToImage(canvastext, canvastext.width,  canvastext.height,'jpeg');
        //let img = canvas.toDataURL("image/png")
        var loadImg = document.createElement('a')
        loadImg.href = img.src
        loadImg.download = 'depth.jpg'
        loadImg.click()
    }

    static captureDepthList(){
        var viewer = window.cesiumViewer;
        var scene = viewer.scene;
        var context = viewer.scene.context;
        var width = viewer.scene.view.viewport.width;
        var height = viewer.scene.view.viewport.height;
        var frameState = scene.frameState;
        var uniformState = context.uniformState;
        var view = scene.defaultView;
        scene.view = view;
        scene.updateFrameState();
        uniformState.update(frameState);
        scene.updateEnvironment();

        var camera = scene.camera;

        // Create a working frustum from the original camera frustum.
        var frustum;
        var scratchPerspectiveFrustum = new Cesium.PerspectiveFrustum();
        if (Cesium.defined(camera.frustum.fov)) {
            frustum = camera.frustum.clone(scratchPerspectiveFrustum);
        }
        var frustumCommandsList = view.frustumCommandsList;
        var numFrustums = frustumCommandsList.length;
        // var pixelsList = [];
        // for (var i = 0; i < numFrustums; ++i) {
        //
        // }
        let pd = scene._picking.getPickDepth(scene,numFrustums-1);
        //get depth

        var pixels = context.readPixels({
            x: 0,
            y: 0,
            width: viewer.scene.view.viewport.width,
            height: viewer.scene.view.viewport.height,
            framebuffer: pd._framebuffer
        });
        var scratchPackedDepth = new Cesium.Cartesian4();
        var packedDepthScale = new Cesium.Cartesian4(
            1.0,
            1.0 / 255.0,
            1.0 / 65025.0,
            1.0 / 16581375.0
        );


        let depthlist = [];
        //原点在左下角
        for (let h = 0; h < height; h++) {
            for(let w = 0;w<width;w++) {
                // let h2 = height - h - 1;
                let i = h*width+w;
                let packedDepth = Cesium.Cartesian4.unpack(pixels, i * 4, scratchPackedDepth);
                Cesium.Cartesian4.divideByScalar(packedDepth, 255.0, packedDepth);
                let depth = Cesium.Cartesian4.dot(packedDepth, packedDepthScale);
                // var log2Depth = depth * uniformState.log2FarDepthFromNearPlusOne;
                // var depthFromNear = Math.pow(2.0, log2Depth) - 1.0;
                // depth = (far * (1.0 - near / (depthFromNear + near))) / (far - near);
                depthlist.push(depth);
            }
        }

        let renderedFrustum = view.frustumCommandsList[numFrustums-1];
        // frustum.near =
        //     renderedFrustum.near *
        //     (i !== 0 ? scene.opaqueFrustumNearOffset : 1.0);
        frustum.near = renderedFrustum.near ;
        frustum.far = renderedFrustum.far;
        uniformState.updateFrustum(frustum);


        // for (let h = 0; h < height; h++) {
        //     for(let w = 0;w<width;w++) {
        //         let h2 = height - h - 1;
        //         let i = h2*width+w;
        //         let packedDepth = Cesium.Cartesian4.unpack(pixels, i * 4, scratchPackedDepth);
        //         Cesium.Cartesian4.divideByScalar(packedDepth, 255.0, packedDepth);
        //         let depth = Cesium.Cartesian4.dot(packedDepth, packedDepthScale);
        //         // var log2Depth = depth * uniformState.log2FarDepthFromNearPlusOne;
        //         // var depthFromNear = Math.pow(2.0, log2Depth) - 1.0;
        //         // depth = (far * (1.0 - near / (depthFromNear + near))) / (far - near);
        //         depthlist.push(depth);
        //     }
        // }
        // var near = frustum.near;
        // var far = frustum.far;
        return depthlist;
    }
    static download(name, data) {
        var urlObject = window.URL || window.webkitURL || window;
        var downloadData = new Blob([data]);
        var save_link = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
        save_link.href = urlObject.createObjectURL(downloadData);
        save_link.download = name;
        var ev = document.createEvent("MouseEvents");
        ev.initMouseEvent(
            "click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null
        );
        save_link.dispatchEvent(ev);
    }
    static captureDepth(){
        let viewer = window.cesiumViewer;
        let width = viewer.scene.view.viewport.width;
        let height = viewer.scene.view.viewport.height;
        var scene = viewer.scene;
        var context = viewer.scene.context;
        var frameState = scene.frameState;
        var uniformState = context.uniformState;
        var view = scene.defaultView;
        scene.view = view;
        scene.updateFrameState();
        uniformState.update(frameState);
        scene.updateEnvironment();

        var camera = scene.camera;

        // Create a working frustum from the original camera frustum.

        var frustumCommandsList = view.frustumCommandsList;
        var numFrustums = frustumCommandsList.length;
        var pixelsList = [];
        var frustumList = [];
        for (var i = 0; i < numFrustums; ++i) {
            let pd = scene._picking.getPickDepth(scene, i);
            //get depth

            var pixels = context.readPixels({
                x: 0,
                y: 0,
                width: viewer.scene.view.viewport.width,
                height: viewer.scene.view.viewport.height,
                framebuffer: pd._framebuffer
            });
            pixelsList.push(pixels);

            var frustum;
            var scratchPerspectiveFrustum = new Cesium.PerspectiveFrustum();
            if (Cesium.defined(camera.frustum.fov)) {
                frustum = camera.frustum.clone(scratchPerspectiveFrustum);
            }
            frustum.near = frustumCommandsList[i].near;
            frustum.far = frustumCommandsList[i].far;
            frustum.invporj = new Cesium.Matrix4();
            Cesium.Matrix4.inverse(frustum.projectionMatrix,frustum.invporj );
            frustumList.push(frustum);
        }

        var scratchPackedDepth = new Cesium.Cartesian4();
        var packedDepthScale = new Cesium.Cartesian4(
            1.0,
            1.0 / 255.0,
            1.0 / 65025.0,
            1.0 / 16581375.0
        );

        let poslist = [];
        //原点在左下角
        for (let h = 0; h < height; h++) {
            for(let w = 0;w<width;w++) {
                let pos = new Cesium.Cartesian3(0,0,0);
                // let h2 = height - h - 1;
                for (let i = 0; i < numFrustums; ++i) {
                    let index = h*width+w;
                    let packedDepth = Cesium.Cartesian4.unpack(pixelsList[i], index * 4, scratchPackedDepth);
                    Cesium.Cartesian4.divideByScalar(packedDepth, 255.0, packedDepth);
                    let depth = Cesium.Cartesian4.dot(packedDepth, packedDepthScale);
                    // var log2Depth = depth * uniformState.log2FarDepthFromNearPlusOne;
                    // var depthFromNear = Math.pow(2.0, log2Depth) - 1.0;
                    // depth = (far * (1.0 - near / (depthFromNear + near))) / (far - near);
                    if(depth > 0 && depth < 1.0) {
                        pos = MPos.drawingBufferToWgs84Coordinates(scene,frustumList[i], new Cesium.Cartesian2(w, h), depth);
                        break;
                    }
                }
                poslist.push(pos);
            }
        }

        let posarrtxt = [];
        for (let i = 0; i < poslist.length; ++i) {
            let pos = poslist[i];
            posarrtxt.push("" + pos.x+","+pos.y+","+pos.z);
        }
        var jsontext = posarrtxt.join("\n");
        //var jsontext=JSON.stringify(posarr);
        MPos.download("save.txt",jsontext);

        // let renderedFrustum = view.frustumCommandsList[numFrustums-1];
        // // frustum.near =
        // //     renderedFrustum.near *
        // //     (i !== 0 ? scene.opaqueFrustumNearOffset : 1.0);
        // frustum.near = renderedFrustum.near ;
        // frustum.far = renderedFrustum.far;
        // uniformState.updateFrustum(frustum);
        //
        // let posarr = [];
        // const ellipsoid = window.cesiumViewer.scene.globe.ellipsoid || Cesium.Ellipsoid.WGS84;
        // for (var h = 0; h < height; h++) {
        //     for(var w = 0;w<width;w++) {
        //         let i = h*width+w;
        //         let depth = depthlist[i];
        //         let pos = new Cesium.Cartesian3(0,0,0);
        //         if(depth > 0 && depth < 1.0){
        //             pos = MPos.drawingBufferToWgs84Coordinates(viewer.scene, new Cesium.Cartesian2(w,h),depth);
        //             // const cartographic = Cesium.Cartographic.fromCartesian(pos, ellipsoid);
        //             // let lon = cartographic.longitude;
        //             // let lat = cartographic.latitude;
        //             // let height = cartographic.height;
        //             // lon = Cesium.Math.toDegrees(lon);
        //             // lat = Cesium.Math.toDegrees(lat);
        //             // pos = new Cesium.Cartesian3(lon,lat,height);
        //
        //             // let dd = depth * 10;
        //             // let xx = (w - 512) / 886.784;
        //             // let yy = (h - 384) / 886.784;
        //             // pos = new Cesium.Cartesian3(xx*dd,yy*dd,dd);
        //         }
        //         posarr.push("" + pos.x+","+pos.y+","+pos.z);
        //     }
        // }
        // var jsontext = posarr.join("\n");
        // //var jsontext=JSON.stringify(posarr);
        // MPos.download("save.txt",jsontext);
    }
}